﻿using System;
using System.Windows;
using System.Windows.Media;
using yzrilyzr.util;
using Math = System.Math;

namespace FAQ_UI
{
	public class MyListView : MyAdapterView
	{
		private Logger logger = new Logger("ListView");

		public double getMeasuredValue(UIElement v)
		{
			return isStackV() ? v.DesiredSize.Height : v.DesiredSize.Width;
		}

		public double getScrollBarWidth()
		{
			return 10;
		}

		protected override void fillList(double value)
		{
			double edge = 0;
			if (StackOrientation == StackOrientations.BOTTOM) edge += RenderSize.Height;
			if (StackOrientation == StackOrientations.RIGHT) edge += RenderSize.Width;

			UIElement child = getChildAt(Children.Count - 1);
			if (child != null)
			{
				edge = isStackInv() ? getChildStart(child) : getChildEnd(child);
			}
			fillListEnd(edge, value);
			edge = 0;
			child = getChildAt(0);
			if (child != null)
			{
				edge = isStackInv() ? getChildEnd(child) : getChildStart(child); ;
			}
			fillListStart(edge, value);
		}

		protected override void OnRender(DrawingContext dc)
		{
			base.OnRender(dc);
			if (Children.Count == 0) { return; }
			double mg = 1;
			Pen pen = new Pen();
			double barWidth = getScrollBarWidth() - 2 * mg;
			double rw = RenderSize.Width;
			double rh = RenderSize.Height;
			double a = mStartViewIndex + 1 + Math.Abs(mDisplayOffset / getMeasuredValue(getChildAt(0)));
			UIElement endC = getChildAt(Children.Count - 1);
			try
			{
				if (StackOrientation == StackOrientations.TOP)
				{
					double top = rh * (a) / getCount();
					double barHeight = rh * Math.Abs(a - mEndViewIndex - (Math.Abs(getChildStart(endC) - rh) / getMeasuredValue(endC))) / getCount();
					if (barHeight > rh) { return; }
					Rect dst = new Rect(rw - barWidth - 2 * mg, top, barWidth, barHeight);
					dc.DrawRoundedRectangle(Theme.AccentBrush, pen, dst, dst.Width / 2, dst.Width / 2);
				}
				else if (StackOrientation == StackOrientations.BOTTOM)
				{
					double bottom = rh - rh * a / getCount();
					double b = Math.Abs(a - mEndViewIndex) - Math.Abs(getChildStart(endC)) / getMeasuredValue(endC);
					double barHeight = rh * b / getCount();
					if (barHeight > rh) { return; }
					Rect dst = new Rect(rw - barWidth - 2 * mg, bottom - barHeight, barWidth, barHeight);
					dc.DrawRoundedRectangle(Theme.AccentBrush, pen, dst, dst.Width / 2, dst.Width / 2);
				}
			}
			catch (Exception ex) { }
		}

		protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo info)
		{
			logger.i("OnRenderSizeChanged", info);
			mMaxValue = Double.MaxValue;
			onScrollChange();
		}

		protected override void positionItems(double value)
		{
			if (Children.Count > 0)
			{
				mDisplayOffset += value;
				double start = mDisplayOffset;
				if (StackOrientation == StackOrientations.BOTTOM) start += RenderSize.Height;
				if (StackOrientation == StackOrientations.RIGHT) start += RenderSize.Width;

				double maxW = HorizontalAlignment == System.Windows.HorizontalAlignment.Stretch ? RenderSize.Width : 0;
				double maxH = VerticalAlignment == System.Windows.VerticalAlignment.Stretch ? RenderSize.Height : 0;
				for (int i = 0; i < Children.Count; i++)
				{
					UIElement child = getChildAt(i);
					//ViewHolder holder = (ViewHolder)child.GetValue(ViewHolder.k);
					//holder.set(mStartViewIndex + 1 + i, DataSource[mStartViewIndex + 1 + i], DataSource);

					double childValue = getMeasuredValue(child);//w or h
					if (StackOrientation == StackOrientations.BOTTOM)
					{
						layoutChild(child, getBoundX(), start - childValue, getBoundX() + Math.Min(Math.Max(child.DesiredSize.Width, maxW), RenderSize.Width), start);
					}
					else if (StackOrientation == StackOrientations.RIGHT)
					{
						layoutChild(child, start - childValue, getBoundY(), start, getBoundY() + Math.Min(Math.Max(child.DesiredSize.Height, maxH), RenderSize.Height));
					}
					else if (StackOrientation == StackOrientations.TOP)
					{
						layoutChild(child, getBoundX(), getBoundY() + start, getBoundX() + Math.Min(Math.Max(child.DesiredSize.Width, maxW), RenderSize.Width), getBoundY() + start + childValue);
					}
					else if (StackOrientation == StackOrientations.LEFT)
					{
						layoutChild(child, getBoundX() + start, getBoundY(), getBoundX() + start + childValue, getBoundY() + Math.Min(Math.Max(child.DesiredSize.Height, maxH), RenderSize.Height));
					}
					if (isStackInv()) start -= childValue;
					else start += childValue;
				}
			}
		}

		protected override void removeNonVisibleItems(double value)
		{
			UIElement child = getChildAt(0);
			double content = isStackV() ? RenderSize.Height : RenderSize.Width;
			while (child != null && (isStackInv() ? getChildStart(child) + value > content : getChildEnd(child) + value < 0))
			{
				if (isStackInv()) mDisplayOffset -= getMeasuredValue(child);
				else mDisplayOffset += getMeasuredValue(child);
				mRecycler.put(this, child);
				mStartViewIndex++;
				child = getChildAt(0);
			}
			child = getChildAt(Children.Count - 1);
			while (child != null && (isStackInv() ? getChildEnd(child) + value < 0 : getChildStart(child) + value > content))
			{
				mRecycler.put(this, child);
				mEndViewIndex--;
				child = getChildAt(Children.Count - 1);
			}
		}

		private void fillListEnd(double edge, double value)
		{
			double mValue = isStackV() ? RenderSize.Height : RenderSize.Width;
			while ((isStackInv() ? edge + value > 0 : edge + value < mValue) && mEndViewIndex < getCount())
			{
				UIElement child = addViewHolderEnd();
				double me = getMeasuredValue(child);
				if (isStackInv())
				{
					edge -= me;
				}
				else
				{
					edge += me;
				}
				if (mEndViewIndex >= getCount())
				{
					if (isStackInv()) mMaxValue = mCurrentValue - edge;
					else mMaxValue = mCurrentValue + edge - mValue;
				}
				else mMaxValue = Double.MaxValue;
				if (mMaxValue < 0)
				{
					mMaxValue = 0;
				}
			}
		}

		private void fillListStart(double edge, double value)
		{
			double mValue = isStackV() ? RenderSize.Height : RenderSize.Width;
			while ((isStackInv() ? edge + value < mValue : edge + value > 0) && mStartViewIndex >= 0)
			{
				UIElement child = addViewHolderStart();
				double mea = getMeasuredValue(child);
				if (isStackInv())
				{
					edge += mea;
					mDisplayOffset += mea;
				}
				else
				{
					edge -= mea;
					mDisplayOffset -= mea;
				}
			}
		}

		private double getBoundX()
		{
			return 0;
		}

		private double getBoundY()
		{
			return 0;
		}

		private double getChildEnd(UIElement child)
		{
			return getChildStart(child) + (isStackV() ? child.RenderSize.Height : child.RenderSize.Width);
		}

		private double getChildStart(UIElement child)
		{
			GeneralTransform gt = child.TransformToAncestor(this);
			Point point = gt.Transform(new Point(0, 0));
			double x = point.X;
			double y = point.Y;
			return isStackV() ? y : x;
		}

		private void layoutChild(UIElement child, double l, double t, double r, double b)
		{
			if (isStackV()) r -= getScrollBarWidth();
			Rect rect2 = new Rect(l, t, r - l, b - t); ;
			child.Arrange(rect2);
			//child.SetValue(Panel.ZIndexProperty, (int)GetValue(Panel.ZIndexProperty) - 100);
		}
	}
}